package photonpay

import (
	"crypto"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"net/http"
	"time"

	"gitee.com/wangshh_123/cross-pay-go/src/config"
)

// PhotonPayUtils 处理 PhotonPay 的认证和签名相关功能
type PhotonPayUtils struct {
	appID      string          // PhotonPay 应用 ID
	appSecret  string          // PhotonPay 应用密钥
	privateKey *rsa.PrivateKey // 商户私钥，用于签名
	publicKey  *rsa.PublicKey  // 平台公钥，用于验签
}

// NewPhotonPayUtils 创建 PhotonPayUtils 的新实例
func NewPhotonPayUtils() (*PhotonPayUtils, error) {
	// 检查配置是否已初始化
	if config.GlobalConfig.PhotonPay.AppID == "" {
		return nil, fmt.Errorf("photonpay app_id is not configured")
	}

	if config.GlobalConfig.PhotonPay.AppSecret == "" {
		return nil, fmt.Errorf("photonpay app_secret is not configured")
	}

	if config.GlobalConfig.PhotonPay.MerchantPrivateKey == "" {
		return nil, fmt.Errorf("photonpay merchant_private_key is not configured")
	}

	if config.GlobalConfig.PhotonPay.PlatformPublicKey == "" {
		return nil, fmt.Errorf("photonpay platform_public_key is not configured")
	}

	// 解析商户私钥
	block, _ := pem.Decode([]byte(config.GlobalConfig.PhotonPay.MerchantPrivateKey))
	if block == nil {
		return nil, fmt.Errorf("failed to decode private key PEM")
	}

	var privateKey *rsa.PrivateKey
	var err error

	// 尝试 PKCS#1 格式
	privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		// 如果 PKCS#1 失败，尝试 PKCS#8 格式
		privateKeyInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("failed to parse private key (tried both PKCS#1 and PKCS#8): %v", err)
		}

		var ok bool
		privateKey, ok = privateKeyInterface.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("private key is not RSA")
		}
	}

	// 解析平台公钥
	block, _ = pem.Decode([]byte(config.GlobalConfig.PhotonPay.PlatformPublicKey))
	if block == nil {
		return nil, fmt.Errorf("failed to decode public key PEM")
	}

	publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse public key: %v", err)
	}

	rsaPublicKey, ok := publicKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("public key is not RSA")
	}

	return &PhotonPayUtils{
		appID:      config.GlobalConfig.PhotonPay.AppID,
		appSecret:  config.GlobalConfig.PhotonPay.AppSecret,
		privateKey: privateKey,
		publicKey:  rsaPublicKey,
	}, nil
}

// GenerateAuthHeader 生成 Basic 认证头
func (p *PhotonPayUtils) GenerateAuthHeader() string {
	credentials := fmt.Sprintf("%s/%s", p.appID, p.appSecret)
	return fmt.Sprintf("basic %s", base64.StdEncoding.EncodeToString([]byte(credentials)))
}

// IsTokenValid 检查令牌是否有效
func (p *PhotonPayUtils) IsTokenValid(expiresIn int64) bool {
	return time.Now().Unix() < expiresIn
}

// GenerateSign 生成请求签名（MD5withRSA）
func (p *PhotonPayUtils) GenerateSign(bodyBytes []byte) (string, error) {
	hash := md5.Sum(bodyBytes)
	signature, err := rsa.SignPKCS1v15(rand.Reader, p.privateKey, crypto.MD5, hash[:])
	if err != nil {
		return "", fmt.Errorf("failed to sign: %v", err)
	}
	return base64.StdEncoding.EncodeToString(signature), nil
}

// VerifySign 验证签名
func (p *PhotonPayUtils) VerifySign(body interface{}, signature string) (bool, error) {
	bodyBytes, err := json.Marshal(body)
	if err != nil {
		return false, fmt.Errorf("failed to marshal body: %v", err)
	}

	hash := sha256.Sum256(bodyBytes)
	signatureBytes, err := base64.StdEncoding.DecodeString(signature)
	if err != nil {
		return false, fmt.Errorf("failed to decode signature: %v", err)
	}

	err = rsa.VerifyPKCS1v15(p.publicKey, crypto.SHA256, hash[:], signatureBytes)
	if err != nil {
		return false, nil
	}

	return true, nil
}

// TokenResponse 令牌响应结构
type TokenResponse struct {
	Code string `json:"code"`
	Data struct {
		ExpiresIn        int64  `json:"expiresIn"`
		RefreshExpiresIn int64  `json:"refreshExpiresIn"`
		RefreshToken     string `json:"refreshToken"`
		Token            string `json:"token"`
	} `json:"data"`
	Msg string `json:"msg"`
}

// GetAccessToken 获取访问令牌
// 返回:
//   - string: 访问令牌
//   - string: 刷新令牌
//   - int64: 过期时间（秒）
//   - int64: 刷新令牌过期时间（秒）
//   - error: 错误信息
func (p *PhotonPayUtils) GetAccessToken() (string, string, int64, int64, error) {
	url := fmt.Sprintf("%s/oauth2/token/accessToken", config.GlobalConfig.PhotonPay.GatewayURL)

	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return "", "", 0, 0, fmt.Errorf("create request failed: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", p.GenerateAuthHeader())

	client := &http.Client{
		Timeout: 10 * time.Second,
	}
	resp, err := client.Do(req)
	if err != nil {
		return "", "", 0, 0, fmt.Errorf("do request failed: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", "", 0, 0, fmt.Errorf("read response failed: %v", err)
	}

	var tokenResp TokenResponse
	if err := json.Unmarshal(body, &tokenResp); err != nil {
		return "", "", 0, 0, fmt.Errorf("unmarshal response failed: %v", err)
	}

	if tokenResp.Code != "0000" {
		return "", "", 0, 0, fmt.Errorf("get token failed: %s", tokenResp.Msg)
	}

	return tokenResp.Data.Token, tokenResp.Data.RefreshToken, tokenResp.Data.ExpiresIn, tokenResp.Data.RefreshExpiresIn, nil
}

// TestSign 测试签名生成和验证功能
func (p *PhotonPayUtils) TestSign() error {
	testBody := map[string]interface{}{
		"requestId": "1001",
	}

	fmt.Println("Testing signature generation and verification...")
	fmt.Printf("Test data: %+v\n", testBody)

	bodyBytes, err := json.Marshal(testBody)
	if err != nil {
		return fmt.Errorf("failed to marshal testBody: %v", err)
	}

	signature, err := p.GenerateSign(bodyBytes)
	if err != nil {
		return fmt.Errorf("failed to generate signature: %v", err)
	}
	fmt.Printf("Generated signature: %s\n", signature)

	valid, err := p.VerifySign(testBody, signature)
	if err != nil {
		return fmt.Errorf("failed to verify signature: %v", err)
	}
	fmt.Printf("Signature verification result: %v\n", valid)

	return nil
}
